﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using System.Xml;
using WindowsPhone.Recipes.Push.Messasges;

namespace Hangout.Web.Core.PushNotifications
{
    public class PushNotifications
    {

        public static void Subscribe(int userId,Uri channelUri,ref Model.HangoutDBEntities context)
        {
            Model.PushNotification notification = GetPushNotification(userId, ref context);
            bool flag = false;
            if (notification == null)
            {
                flag = true;
                notification = new Model.PushNotification();
                notification.UserID = userId;

            }

            notification.ChannelURI = channelUri.ToString();

            if (flag)
            {
                context.AddToPushNotifications(notification);
            }

            context.SaveChanges();
        }

        public static void Unsubscribe(int userId, ref Model.HangoutDBEntities context)
        {
            Model.PushNotification notification = GetPushNotification(userId, ref context);
            if (notification != null)
            {
                context.PushNotifications.DeleteObject(notification);
                context.SaveChanges();
            }
        }

        public static Model.PushNotification GetPushNotification(int userId, ref Model.HangoutDBEntities context)
        {
            return context.PushNotifications.Where(o => o.UserID==userId).SingleOrDefault();
        }

        public static bool Exists(int userId,ref Model.HangoutDBEntities context)
        {
            if (GetPushNotification(userId, ref context) == null)
            {
                return false;
            }
            return true;
        }

        private static byte[] PrepareMeetupRAWPayload(int userId, DateTime datetime)
        {
            MemoryStream stream = new MemoryStream();

            XmlWriterSettings settings = new XmlWriterSettings() { Indent = true, Encoding = Encoding.UTF8 };
            XmlWriter writer = XmlTextWriter.Create(stream, settings);

            writer.WriteStartDocument();
            writer.WriteStartElement("MeetupUpdate");

            writer.WriteStartElement("UserID");
            writer.WriteValue(userId);
            writer.WriteEndElement();

            writer.WriteStartElement("DateTime");
            writer.WriteValue(datetime);
            writer.WriteEndElement();


            writer.WriteEndElement();
            writer.WriteEndDocument();
            writer.Close();

            byte[] payload = stream.ToArray();
            return payload;
        }

        public static void SendMeetupRequestNotificationRAW(int fromUserId,int toUserId,ref Model.HangoutDBEntities context)
        {

            RawPushNotificationMessage rawPushNotificationMessage = new RawPushNotificationMessage(MessageSendPriority.High);
            
            //Prepare payload
            byte[] payload = PrepareMeetupRAWPayload(fromUserId, DateTime.Now);

            rawPushNotificationMessage.RawData = payload;

            if (Exists(toUserId, ref context))
            {
                rawPushNotificationMessage.Send(new Uri(GetPushNotification(toUserId, ref context).ChannelURI, UriKind.RelativeOrAbsolute));
            }

        }

        public static void SendNotification(Model.Notification Notification,Model.HangoutDBEntities context)
        {
            SendRawNotification(Notification, ref context); //send RAW Notification :)
            SendTileNotification(Notification,ref context); //send a Tile notification :)

        }

        private static void SendTileNotification(Model.Notification Notification, ref Model.HangoutDBEntities context)
        {
            try
            {
                // Get the URI that the Microsoft Push Notification Service returns to the Push Client when creating a notification channel.
                // Normally, a web service would listen for URIs coming from the web client and maintain a list of URIs to send
                // notifications out to.
                if (Notification == null)
                {
                    return;
                }

                if (Notification.UserID == null)
                {
                    return;
                }

                Model.PushNotification pn = GetPushNotification(Notification.UserID, ref context);


                if(pn==null)
                {
                    return;

                }

                if(pn.ChannelURI==null)
                {
                    return;
                }

                string subscriptionUri = pn.ChannelURI.ToString();


                HttpWebRequest sendNotificationRequest = (HttpWebRequest)WebRequest.Create(subscriptionUri);

                // Create an HTTPWebRequest that posts the Tile notification to the Microsoft Push Notification Service.
                // HTTP POST is the only method allowed to send the notification.
                sendNotificationRequest.Method = "POST";

                // The optional custom header X-MessageID uniquely identifies a notification message. 
                // If it is present, the same value is returned in the notification response. It must be a string that contains a UUID.
                // sendNotificationRequest.Headers.Add("X-MessageID", "<UUID>");

                // Create the Tile message.
                string tileMessage = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
                "<wp:Notification xmlns:wp=\"WPNotification\">" +
                    "<wp:Tile>" +
                      "<wp:BackTitle> Notifications </wp:BackTitle>" +
                      "<wp:BackContent>" + Notifications.Notification.GetUnreadNotificationCount(Notification.UserID,context) + " new items.</wp:BackContent>" +
                   "</wp:Tile> " +
                "</wp:Notification>";

                // Set the notification payload to send.
                byte[] notificationMessage = Encoding.Default.GetBytes(tileMessage);

                // Set the web request content length.
                sendNotificationRequest.ContentLength = notificationMessage.Length;
                sendNotificationRequest.ContentType = "text/xml";
                sendNotificationRequest.Headers.Add("X-WindowsPhone-Target", "token");
                sendNotificationRequest.Headers.Add("X-NotificationClass", "1");


                using (Stream requestStream = sendNotificationRequest.GetRequestStream())
                {
                    requestStream.Write(notificationMessage, 0, notificationMessage.Length);
                }

                // Send the notification and get the response.
                HttpWebResponse response = (HttpWebResponse)sendNotificationRequest.GetResponse();
                string notificationStatus = response.Headers["X-NotificationStatus"];
                string notificationChannelStatus = response.Headers["X-SubscriptionStatus"];
                string deviceConnectionStatus = response.Headers["X-DeviceConnectionStatus"];

                // Display the response from the Microsoft Push Notification Service.  
                // Normally, error handling code would be here. In the real world, because data connections are not always available,
                // notifications may need to be throttled back if the device cannot be reached.
                

            }
            catch (Exception ex)
            {
                
            }

        }

        private static Model.HangoutDBEntities SendRawNotification(Model.Notification Notification, ref Model.HangoutDBEntities context)
        {
            //send a push notification to the user. :)
            try
            {
                // Get the URI that the Microsoft Push Notification Service returns to the push client when creating a notification channel.
                // Normally, a web service would listen for URIs coming from the web client and maintain a list of URIs to send
                // notifications out to.

                RawPushNotificationMessage rawPushNotificationMessage = new RawPushNotificationMessage(MessageSendPriority.High);

                //Prepare payload
                byte[] payload = PrepareNotificationRAWPayload(Notification);

                rawPushNotificationMessage.RawData = payload;

                if (Exists(Notification.UserID, ref context))
                {
                    rawPushNotificationMessage.Send(new Uri(GetPushNotification(Notification.UserID, ref context).ChannelURI, UriKind.RelativeOrAbsolute));
                }
            }
            catch (Exception ex)
            {
                //report exception

               
            }
            return context;
        }

        private static byte[] PrepareNotificationRAWPayload(Model.Notification notification)
        {
            MemoryStream stream = new MemoryStream();

            XmlWriterSettings settings = new XmlWriterSettings() { Indent = true, Encoding = Encoding.UTF8 };
            XmlWriter writer = XmlTextWriter.Create(stream, settings);

            writer.WriteStartDocument();
            writer.WriteStartElement("NotificationUpdate");

            writer.WriteStartElement("UserID");
            writer.WriteValue(notification.UserID);
            writer.WriteEndElement();

            writer.WriteStartElement("NotificationID");
            writer.WriteValue(notification.NotificationID);
            writer.WriteEndElement();

            writer.WriteStartElement("Text");
            writer.WriteValue(notification.Text);
            writer.WriteEndElement();

            writer.WriteStartElement("MetaData");
            writer.WriteValue(notification.MetaData);
            writer.WriteEndElement();

            writer.WriteStartElement("DateTime");
            writer.WriteValue(notification.DateTimeStamp);
            writer.WriteEndElement();

            writer.WriteEndElement();
            writer.WriteEndDocument();
            writer.Close();

            byte[] payload = stream.ToArray();
            return payload;
        }
    }
}